import React from 'react';
import './check.scss';
import Select from "react-select";
import {Link} from "react-router-dom";
import {getRandomString} from "auxiliaries/extends/random";
import {observer} from 'mobx-react';
import {observable, action, computed, autorun, toJS} from 'mobx.collection';
import {DateFormat, formatClassList, formatToCreateDate} from "auxiliaries/extends/format";
import {Storage} from 'auxiliaries/session/overload/storage';
import 'weui';
import {uploader as WEUploader, datePicker as DatePicker, gallery as GalleryView, picker as MultiPicker} from 'weui.js';
import {alert, confirm, loaded, loading, notify} from 'components/state/toast';
import {LimitUrl} from "fetch";
import FetchController from "fetch";
import BROWSERTYPES from "auxiliaries/extends/browser-type";
import {WeChat as Wechat, WeChat} from "auxiliaries/extends/wechat";
import WeChatController from "api/wechat";
import {UploadController} from "api/upload";
import BROWSERTYPE from "auxiliaries/extends/browser-type";
import {Hint} from "components/state/data-load";

function classListProcess(_className, fontSize) {
    return formatClassList(_className, fontSize);
}

function updateProperty(keys, value) {
    let props = this;
    let split = keys.split('.');
    let arrayLength = split.length - 1;
    split.forEach((key, index) => {
        if (index >= arrayLength) {
            if (!!value?.currentTarget?.value) {
                props[key] = value.currentTarget.value;
            } else {
                props[key] = value;
            }
        } else {
            props = props[key] || {};
        }
    });
}

function createIcon(icoClassName) {
    return icoClassName ?
        <div className={
            [
                "ico",
                icoClassName
            ].filter(Boolean).join(' ')
        }/> :
        null;
}

@observer
class ReactSelect extends React.Component {
    #refElement;
    @observable option;

    @computed get value() {
        return this.option?.value
    }

    @computed get label() {
        return this.option?.label
    }

    @action
    handleChange(selectedOption) {
        this.option = selectedOption;

        this.props.onChange?.(selectedOption);
    }

    @action
    componentWillMount() {
        this.option = this.props?.value;
    }

    componentWillUnmount() {
        this.#disposer();
    }

    #disposer = autorun(() => {
        this.#refElement?.setValue(this.option);
    });

    render() {
        let className = this.props.className || '';
        let classList = className instanceof Array ? className : className.split(' ');

        if (classList.join(' ').indexOf('font-size') < 0) {
            classList.push('font-size-14');
        }

        let {...rest} = this.props;

        // noinspection JSUnusedGlobalSymbols
        return (
            <Select {...rest}
                    className={[
                        '--react-element',
                        'react-select',
                        ...classList
                    ].join(' ')}
                    ref={_ => this.#refElement = _}
                    isSearchable={this.props?.isSearchable || false}
                    classNamePrefix="react-select"
                    onChange={this.handleChange.bind(this)}
                    styles={{
                        ...this.styles,

                        option: (provided, state) => ({
                            ...provided,
                        }),
                        valueContainer: (provided) => ({
                            ...provided,
                            padding: "0"
                        }),
                        control: (provided, state) => ({
                            ...provided,
                            border: "none",
                            boxShadow: "none",
                            borderRadius: "none",
                            padding: "0"
                        })
                    }}/>
        );
    }
}

@observer
class ReactLinkSelect extends React.Component {
    #storage;
    @observable value;
    @observable option;

    constructor(_, context) {
        super(_, context);

        // if (!this.props.type) {
        //     throw 'props.type is required';
        // }

        if (this.props.type) {
            this.#storage = Storage(this.props.type);
        }
    }

    componentWillMount() {
        //todo 有待完善逻辑部分
        if (this.#storage) {
            this.value = this.#storage.get()?.label || '';
            this.option = this.#storage.get();
        }
    }

    componentWillUpdate() {

        if (this.#storage) {
            this.value = this.#storage.get()?.label || '';
            this.option = this.#storage.get();
        }
    }

    render() {
        let {label} = this.#storage?.get() || {};

        let {
            onClick,
            className = '',
            icoClassName,
            childrenText,
            highlight,
            title,
            disabled,
            showRightButton = true,
            ...rest
        } = this.props;
        let classList = className instanceof Array ? className : className.split(' ');

        return (
            <div className={[
                "--react-element --react-link",
                ...classList,
                highlight || label || this.props?.label ? "" : "off"
            ].join(' ')}
                 onClick={onClick}
                 {...rest}>
                {createIcon(icoClassName)}
                <div className="group">
                    <LinkSelectable disabled={disabled}
                                    className={"--link placeholder-link-highlight"}
                                    to={this.props.path || ''}>
                        <span>{title || label || this.props?.label || this.props?.placeholder}</span>
                    </LinkSelectable>
                </div>
                {this.props?.children}
                {childrenText ?
                    <LinkSelectable disabled={disabled} to={this.props.path || ''}>{childrenText}</LinkSelectable>
                    : null}
                {showRightButton &&
                <LinkSelectable disabled={disabled} to={this.props.path || ''} className="right-ico"/>}
            </div>
        );
    }
}

export class ReactLabel extends React.Component {
    render() {
        let {
            className = '',
            icoClassName,
            onClick,
            title,
            rightText,
            label,
            ...rest
        } = this.props;
        let classList = className instanceof Array ? className : className.split(' ');

        return (
            <div className={[
                "--react-element --react-label",
                ...classList
            ].filter(Boolean).join(' ')}
                 onClick={onClick}
                 {...rest}>
                {createIcon(icoClassName)}
                <div className={"group"}>
                    <span className={"--react-label-title"}>{title || label}</span>
                </div>
                {
                    rightText ?
                        <span className={"--right-text"}>{rightText}</span>
                        : null
                }
                {this.props.children}
            </div>
        );
    }
}

export class ReactLabelList extends React.Component {
    render() {
        let {
            list = [],
            onClick,
            ...rest
        } = this.props;

        return list.map(x => (
            <ReactLabel key={x.label + "-Label"} {...x} onClick={onClick?.bind(this, x)} {...rest}/>
        ))
    }
}

class ReactInput extends React.Component {
    #ReactInputElement;
    value;

    componentWillMount() {
        this.value = this.props.value || '';
    }

    onInput(e) {
        this.value = e.target.value;
        this.props?.onInput?.(e);
    }

    onChange(e) {
        this.value = e.currentTarget.value;
        this.props?.onChange?.(e);
    }

    setValue(value) {
        if (this.#ReactInputElement) {
            this.#ReactInputElement.value = value;
        }
    }

    render() {
        let {
            rootClassName,
            className,
            defaultValue,
            type: inputType = 'text',
            onBlur,
        } = this.props;
        let rootList = [
            "--react-element",
        ].concat(classListProcess(rootClassName));
        let containerList = classListProcess(className);

        return (
            <div className={rootList.join(' ')}>
                {createIcon(this.props['icoClassName'])}
                <div className={"group"}>
                    <input ref={_ => this.#ReactInputElement = _}
                           className={containerList.join(' ')}
                           onBlur={onBlur}
                           type={inputType}
                           onInput={(e) => this.onInput(e)}
                           onChange={this.onChange.bind(this)}
                           value={this.props.value}
                           defaultValue={defaultValue}
                           placeholder={this.props?.placeholder}
                           disabled={this.props?.disabled}
                           readOnly={this.props?.readonly}
                    />
                </div>
                {this.props.children}
            </div>
        );
    }
}

export class ReactButton extends React.Component {
    render() {
        let {
            className = '',
            to,
            ...rest
        } = this.props;
        let classListResult = [
            "--react-button",
            "touch-active",
        ].concat(classListProcess(className));

        if (to) {
            return (
                <Link to={to} className={classListResult.join(' ')} {...rest}>{this.props.children}</Link>
            );
        }
        return (
            <button className={classListResult.join(' ')} {...rest}>{this.props.children}</button>
        );
    }
}

@observer
class ReactSearch extends React.Component {
    #InputID = getRandomString(8);
    @observable SearchValue = '';

    @action
    onChange() {
        this.SearchValue = document.getElementById(this.#InputID).value;
    }

    @action
    onClear() {
        this.SearchValue = '';
        document.getElementById(this.#InputID).value = this.SearchValue;
    }

    render() {
        let {
            type: inputType = 'text',
            placeholder,
            className,
            containerClassName,
            readOnly,
            disabled,
            refs,
            onSubmit
        } = this.props || {};
        let classList = [
            "--react-search flex-start",
        ].concat(classListProcess(className));
        let containerClassList = [
            "--container",
            "flex-start"
        ].concat(classListProcess(containerClassName));

        return (
            <form onSubmit={_ => {
                if (this.returning === true) {
                    return;
                }
                this.returning = true;
                _.preventDefault();
                onSubmit?.();
                this.returning = false;
            }}>
                <div className={classList.join(' ')}>
                    <div className={containerClassList.join(' ')}>
                        <label htmlFor={this.#InputID}/>
                        <div className="--input">
                            <input ref={refs}
                                   id={this.#InputID}
                                   type={inputType}
                                   autoFocus={true}
                                   className={"font-size-28"}
                                   onFocus={_ => this.onChange(_)}
                                   onInput={_ => this.onChange(_)}
                                   onBlur={() => {
                                       if (this.returning === true) {
                                           return;
                                       }
                                       if (!document.getElementById(this.#InputID).value) {
                                           return;
                                       }
                                       this.returning = true;
                                       onSubmit?.();
                                       this.returning = false;
                                   }}
                                   readOnly={readOnly}
                                   disabled={disabled}
                                   placeholder={placeholder}/>
                            <button type={"submit"} style={{display: "none"}}/>
                            <div className={"--close" + (this.SearchValue ? ' on' : '')} onClick={() => this.onClear()}>
                                <span className={"--bg"}/>
                            </div>
                        </div>
                    </div>
                </div>
            </form>
        );
    }
}

class LinkSelectable extends React.Component {
    render() {
        let {to, children, ...rest} = this.props;
        return (
            to ?
                <Link to={to} {...rest}>
                    {children}
                </Link>
                :
                <div {...rest}>
                    {children}
                </div>
        )
    }
}

@observer
class ReactTextArea extends React.Component {
    #Element;

    @computed get value() {
        return this.#Element?.value;
    }

    setValue(value) {
        if (this.#Element) {
            this.#Element.value = value;
        }
    }

    render() {
        let {className, ...rest} = this.props;

        return (
            <label className={"--react-textarea"}>
                <textarea ref={_ => this.#Element = _} {...rest}/>
            </label>
        )
    }
}

@observer
class ReactDatePicker extends React.Component {
    @observable time;
    #id = 'ELEMENT-DATE-PICKER-' + getRandomString();

    constructor(props) {
        super(props);

        while (document.getElementById(this.#id)) {
            this.#id = 'ELEMENT-DATE-PICKER-' + getRandomString();
        }
    }

    componentWillMount() {
        if (this.props.defaultValue || this.props.value) {
            this.time = formatToCreateDate(this.props.defaultValue || this.props.value);
        }
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value) {
            this.time = formatToCreateDate(nextProps.value);
        } else {
            this.time = '';
        }
    }

    componentWillUpdate() {
        //update
    }

    @action
    onClick(e) {
        if (this.props.disabled || this.props.readOnly) {
            return;
        }

        let options = this.props.options || {};
        if (this.props.startDate) {
            options.start = new Date(this.props.startDate);
        }
        if (this.props.endDate) {
            if (+this.props.endDate < 10000) {
                options.end = new Date(this.props.endDate + 1, 0, 0);
            } else {
                options.end = new Date(this.props.endDate);
            }
        }

        let defaultValue = this.props.value;
        if (defaultValue) {
            defaultValue = new Date(defaultValue);

            defaultValue = [defaultValue.getFullYear(), defaultValue.getMonth() + 1, defaultValue.getDate()];
        } else {
            let now = new Date();

            if (options.start && now.getTime() < options.start.getTime()) {
                now = options.start;
            }

            defaultValue = [now.getFullYear(), now.getMonth() + 1, now.getDate()];
        }

        DatePicker({
            ...options,
            defaultValue,
            onConfirm: (timeList) => {
                this.time = formatToCreateDate(timeList.map(x => x.value).join('/'));
                if (this.time === 'Invalid Date') {
                    this.time = null;
                }
                this.props.onChange?.(this.time);
            },
            id: this.#id
        });
        this.props.onClick?.(e);
    }

    render() {
        let className = this.props.className || '';
        let classList = className instanceof Array ? className : className.split(' ');
        let {
            rightText, format, disabled, readOnly
        } = this.props;

        return (
            <div id={this.#id} className={[
                "--react-element --react-link",
                ...classList,
                this.time || this.props?.label ? "" : "off"
            ].join(' ')} onClick={this.onClick.bind(this)} disabled={disabled} readOnly={readOnly}>
                {createIcon(this.props['icoClassName'])}
                <div className="group">
                    <a className={"--link placeholder-link-highlight"}>
                        <span>{this.props?.label || this.props?.placeholder}</span>
                    </a>
                </div>
                {
                    this.time ?
                        <span>{DateFormat(this.time, format || 'yyyy年mm月dd日')}</span>
                        : rightText ?
                        <span>{rightText}</span>
                        : null
                }
                {this.props?.children}
                <a className="right-ico"/>
            </div>
        );
    }
}

@observer
class ReactTimePicker extends React.Component {
    #id = 'ELEMENT-DATE-PICKER-' + getRandomString();

    @observable time;

    constructor(props) {
        super(props);

        while (document.getElementById(this.#id)) {
            this.#id = 'ELEMENT-DATE-PICKER-' + getRandomString();
        }
    }

    componentWillMount() {
        this.time = formatToCreateDate(this.props.value);
    }

    @action
    onClick(e) {
        if (this.props.disabled || this.props.readOnly) {
            return;
        }

        let That = this;

        MultiPicker(
            [''],
            [''],
            ' '.repeat(23).split(' ').map((_, i) => (i < 10 ? `0${i}` : i)),
            [':'],
            ' '.repeat(59).split(' ').map((_, i) => (i < 10 ? `0${i}` : i)),
            [''],
            [''],
            {
                defaultValue: ['3', 'A'],
                onConfirm: function onConfirm(result) {
                    let times = result.filter(Boolean).map(x => x.value).join('').split(':');
                    let date = new Date();
                    date.setTime(+times[0] * 60 * 60 * 1000 + +times[1] * 1000 * 60 - 8 * 3600 * 1000);
                    That.time = date;
                    That.props?.onChange?.(times.join(':'), date);
                },
                id: this.#id
            });

        this.props.onClick?.(e);
    }

    render() {
        let className = this.props.className || '';
        let classList = className instanceof Array ? className : className.split(' ');
        let {
            rightText, format, disabled, readOnly
        } = this.props;

        return (
            <div className={[
                "--react-element --react-link",
                ...classList,
                (this.time && this.time !== 'Invalid Date') || this.props?.label ? "" : "off"
            ].join(' ')} onClick={this.onClick.bind(this)} disabled={disabled} readOnly={readOnly}>
                {createIcon(this.props['icoClassName'])}
                <div className="group">
                    <a className={"--link placeholder-link-highlight"}>
                        <span>{this.props?.label || this.props?.placeholder}</span>
                    </a>
                </div>
                {
                    this.time && this.time !== 'Invalid Date' ?
                        <span>{DateFormat(this.time, format || 'HH:MM')}</span>
                        : rightText ?
                        <span>{rightText}</span>
                        : null
                }
                {this.props?.children}
                <a className="right-ico"/>
            </div>
        );
    }
}

@observer
class ReactUpload extends React.Component {
    #id = 'ELEMENT-' + getRandomString(5);
    #previewId = 'ELEMENTPREVIEW-' + getRandomString(5);

    uploadCount = 0;
    @observable uploadList = [];
    @observable initList = [];
    maxCount = 5;

    @computed get returnList() {
        return [].concat(toJS(this.initList)).concat(toJS(this.uploadList)).map(x => x.url).filter(Boolean);
    }

    constructor(props) {
        super(props);

        let elm = document.getElementById(this.#id);
        while (elm) {
            this.#id = getRandomString();
            elm = document.getElementById(this.#id);
        }

        elm = document.getElementById(this.#previewId);
        while (elm) {
            this.#previewId = getRandomString();
            elm = document.getElementById(this.#previewId);
        }

        this.maxCount = this.props.count || 5;
    }

    onPreviewImage(e) {
        // if (BROWSERTYPES.isWeChat) {
        //     //不使用微信WEUI库
        //     return;
        // }

        let target = e.target;

        while (!target.classList.contains('weui-uploader__file') && target) {
            target = target.parentNode;
        }
        if (!target) return;

        let url = target.getAttribute('style') || '';
        let id = target.getAttribute('data-id');
        let removeIndex = this.initList.findIndex(x => +x.id === +id);

        if (url) {
            url = url.match(/url\((.*?)\)/)[1].replace(/"/g, '');
        }
        let gallery = GalleryView(url, {
            className: this.props.disabled ? ' hide-delete-btn' : '',
            onDelete: async () => {
                let ok = await confirm('确定删除该图片？');
                if (ok) {
                    --this.uploadCount;

                    if (BROWSERTYPES.isWeChat) {
                        this.uploadList.splice(id, 1);
                    } else {
                        if (removeIndex >= 0) {
                            this.initList.splice(removeIndex, 1);
                        } else {
                            for (let i = 0, len = this.uploadList.length; i < len; ++i) {
                                let file = this.uploadList[i];
                                if (+file.id === +id) {
                                    file.stop?.();
                                    this.uploadList.splice(i, 1);
                                    break;
                                }
                            }
                            target.remove();
                        }
                    }
                    this.props.onFilesChange?.(this.returnList);
                    gallery.hide();
                }
            }
        });
    }

    onPreviewSingleImage(index) {
        //使用微信JSAPI
        Wechat.PreviewImage(this.uploadList, index);
    }

    componentWillReceiveProps(nextProps) {
        if (toJS(nextProps.initFiles) instanceof Array) {
            if (BROWSERTYPES.isWeChat) {
                this.initList = [...nextProps.initFiles];
            } else {
                this.initList = [...nextProps.initFiles.map((x, i) => ({
                    id: i,
                    url: x
                }))];
            }
        }
    }

    componentDidMount() {
        //GalleryView
        //预览图片

        let That = this;

        if (!BROWSERTYPES.isWeChat) {
            WEUploader(`#${this.#id}`, {
                url: LimitUrl(this.props.baseUrl),
                auto: true,
                type: 'file',
                fileVal: 'file',
                compress: false,
                onBeforeQueued: function onBeforeQueued(files) {
                    if (["image/jpg", "image/jpeg", "image/png", "image/gif"].indexOf(this.type) < 0) {
                        alert('请上传图片');
                        return false;
                    }
                    if (this.size > 10 * 1024 * 1024) {
                        alert('请上传不超过10M的图片');
                        return false;
                    }
                    if (files.length > That.maxCount) {
                        // 防止一下子选中过多文件
                        alert('最多只能上传5张图片，请重新选择');
                        return false;
                    }
                    if (That.uploadCount + 1 > That.maxCount) {
                        alert('最多只能上传' + That.maxCount + '张图片');
                        return false;
                    }

                    ++That.uploadCount;
                },
                onQueued: function onQueued() {
                    let result = That.uploadList.find(x => x.id === this.id);
                    let index = That.uploadList.indexOf(result);
                    if (result) {
                        That.uploadList[index].id = this.id;
                    } else {
                        That.uploadList.push({
                            id: this.id
                        });
                    }
                },
                onBeforeSend: function onBeforeSend(data, headers) {
                    That.props.onBeforeSend?.(this, data, headers);
                    let config = FetchController.getLocalConfig();

                    Object.assign(headers, config);
                    // $.extend(data, { test: 1 }); // 可以扩展此对象来控制上传参数
                    // $.extend(headers, { Origin: 'http://127.0.0.1' }); // 可以扩展此对象来控制上传头部

                    // return false; // 阻止文件上传
                },
                onProgress: function onProgress(procent) {
                    That.props.onProgress?.(this, procent);
                },
                onSuccess: function onSuccess(ret) {
                    That.props.onSuccess?.(this, ret);
                    That.uploadList.find(x => x.id === this.id).url = ret['Data'];
                    That.props.onFilesChange?.(That.returnList);
                },
                onError: function onError(err) {
                    That.props.onError?.(this, err);
                }
            });
        }
    }

    onChange(e) {
        if (BROWSERTYPES.isWeChat) {
            this.uploadList = (this.uploadList || []).concat(e.files);
            this.props.onFilesChange?.([].concat(toJS(this.initList) || [], toJS(this.uploadList)));
        }
    }

    onBeforeChoose() {
        let result = this.uploadList?.length >= this.maxCount;
        if (result) {
            notify('最多只能上传' + this.maxCount + '张图片，请重新选择');
        }
        return result;
    }

    render() {
        let {
            className,
            disabled
        } = this.props;
        return (
            <div className={[
                "--react-upload",
            ].concat(formatClassList(className, 'font-size-30')).join(' ')}>
                <div className="weui-cells weui-cells_form" id={this.#id}>
                    <div className="weui-cell">
                        <div className="weui-cell__bd">
                            <div className="weui-uploader">
                                <div className="weui-uploader__hd">
                                    <p className="weui-uploader__title">{this.props.title || '图片上传'}</p>
                                </div>
                                <div className="weui-uploader__bd">
                                    <ul className="weui-uploader__files" id={this.#previewId}
                                        onClick={this.onPreviewImage.bind(this)}>
                                        {
                                            (this.props.disabled || this.props.readOnly) &&
                                            !(this.initList?.length > 0) &&
                                            !(this.uploadList?.length > 0) ?
                                                <Hint>{this.props.noImgMessage || '暂无图片'}</Hint> : null
                                        }
                                        {
                                            this.initList?.map((x, i) => (
                                                <li className="weui-uploader__file"
                                                    key={x + i}
                                                    data-id={x.id}
                                                    // onClick={this.onPreviewSingleImage.bind(this, i)}
                                                    style={{
                                                        backgroundImage: `url('${x.url}')`
                                                    }}>
                                                </li>
                                            ))
                                        }
                                        {
                                            BROWSERTYPES.isWeChat ?
                                                this.uploadList?.filter(x => this.initList?.indexOf(x) < 0).map((x, i) => (
                                                    <li className="weui-uploader__file"
                                                        key={x + i}
                                                        data-id={i}
                                                        // onClick={this.onPreviewSingleImage.bind(this, i)}
                                                        style={{
                                                            backgroundImage: `url('${x}')`
                                                        }}>
                                                    </li>
                                                )) : null
                                        }
                                    </ul>
                                    {
                                        this.props.disabled ? null :
                                            <div className="weui-uploader__input-box">
                                                <DynamicUploadInput upload={!!BROWSERTYPES.isWeChat}
                                                                    count={5 - (this.uploadList?.length || 0)}
                                                                    disabled={disabled}
                                                                    className="weui-uploader__input"
                                                                    onBeforeClick={this.onBeforeChoose.bind(this)}
                                                                    onChange={this.onChange.bind(this)}
                                                                    type="file" accept="image/*"
                                                                    multiple=""/>
                                                {/*capture="camera"*/}
                                            </div>
                                    }
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

//todo: 看原生的兼容情况来选择是否要更细化版本的判断来使用自定义日期时间控件
@observer
class ReactNativeDate extends React.Component {
    @observable value;
    #DateTimePicker;

    #id = 'ELEMENT-ID-DATE' + getRandomString();
    #style = {
        width: '100%',
        height: '35px',
        position: 'absolute',
        opacity: 0,
        zIndex: 0,
    };

    constructor(props) {
        super(props);

        while (document.getElementById(this.#id)) {
            this.#id = 'ELEMENT-ID-DATE' + getRandomString();
        }

        if (this.props.defaultValue || this.props.value) {
            this.value = formatToCreateDate(this.props.defaultValue || this.props.value);
        }


        this.Condition = this.props.useWechat;
        if (typeof this.Condition !== 'boolean') {
            this.Condition = !BROWSERTYPE.isWeChat;
        }
    }

    dateChange(e) {
        if (this.props.disabled || this.props.readonly) {
            return;
        }
        // updateProperty.bind(this)('value', e);
        if (!this.Condition) {
            this.value = this.#DateTimePicker.value;
        } else {
            this.value = e;
        }
        this.props.onChange?.(e, new Date(typeof this.value === 'string' ? this.value.replace(/[-]/g, '/') : this.value));
    }

    componentWillReceiveProps(nextProps) {
        if (!this.Condition) {
            if (nextProps.value) {
                this.value = formatToCreateDate(nextProps.value);
            }
        }
    }

    render() {
        let {
            title,
            label,
            placeholder,
            className,
            onChange,
            format,
            disabled,
            readOnly,
            startDate,
            endDate,
            defaultValue,
            value,
            useWechat,
            ...rest
        } = this.props;

        if (this.Condition) {
            return <ReactDatePicker className={"margin" + (className ? ` ${className}` : '')} ref={_ => this.DatePicker}
                                    disabled={disabled} readOnly={readOnly} onChange={this.dateChange.bind(this)}
                                    format={format || 'yyyy.mm.dd'}
                                    startDate={startDate}
                                    endDate={endDate}
                                    value={defaultValue || value}
                                    options={this.props.options}
                                    placeholder={this.props.title || "截止日期"}
                                    rightText={this.props.placeholder || "请选择截止日期"}/>;
        }

        let inputOptions = {};
        // if (endDate) {
        //     if (endDate <= 9999 && endDate >= 1000) {
        //         endDate = new Date(endDate + 1, 0, 0);
        //     } else if (typeof endDate === 'string') {
        //         endDate = new Date(endDate);
        //     }
        //     inputOptions['max'] = DateFormat(endDate, 'yyyy-mm-dd');
        // }
        //
        // if (startDate) {
        //     if (startDate <= 9999 && startDate >= 1000) {
        //         startDate = new Date(startDate + 1, 0, 0);
        //     } else if (typeof startDate === 'string') {
        //         startDate = new Date(startDate);
        //     }
        //     inputOptions['min'] = DateFormat(startDate, 'yyyy-mm-dd');
        // }

        //
        return (
            <>
                <input {...rest} {...inputOptions} disabled={disabled} readOnly={readOnly} style={this.#style}
                       ref={_ => this.#DateTimePicker = _}
                    // defaultValue={this.props.defaultValue || DateFormat(new Date(), 'yyyy-mm-dd')}
                    // value={DateFormat(this.value, 'yyyy-mm-dd')}
                       type={"date"}
                       id={this.#id}
                       onChange={this.dateChange.bind(this)}/>
                <label className={["--react-native-date"].concat(formatClassList(className)).join(' ')}
                       style={{
                           position: 'relative',
                           zIndex: 1
                       }}
                       htmlFor={this.#id}>
                    <ReactLinkSelect placeholder={title || label} highlight={!!this.value}>
                        <span>{this.value ? DateFormat(this.value, format || 'yyyy.mm.dd') : placeholder}</span>
                    </ReactLinkSelect>
                </label>
            </>
        );
    }
}

@observer
class ReactNativeTime extends React.Component {
    #id = 'ELEMENT-ID-TIME' + getRandomString();

    #ReactTimeRef;

    @observable value = '';

    constructor(props) {
        super(props);

        while (document.getElementById(this.#id)) {
            this.#id = 'ELEMENT-ID-TIME' + getRandomString();
        }
    }

    timeChange(e, date) {
        if (false && BROWSERTYPES.isWeChat) {
            this.value = this.#ReactTimeRef.value;
        } else {
            this.value = e;
        }

        // updateProperty.bind(this)('value', e);
        this.props.onChange?.(this.value);
    }

    //todo: 准备用WEUI的Multi-Picker，WECHAT就用原生，原生还能用datetime-local
    //https://weui.io/weui.js/
    render() {
        let {
            title,
            label,
            placeholder,
            className,
            onChange,
            format,
            disabled,
            readOnly,
            value,
            ...rest
        } = this.props;
        // return <input type="datetime-local"/>;

        if (true || !BROWSERTYPES.isWeChat) {
            return <ReactTimePicker className={"margin"} ref={_ => this.DatePicker}
                                    disabled={disabled} readOnly={readOnly} onChange={this.timeChange.bind(this)}
                                    format={format || 'HH:MM'}
                                    placeholder={this.props.title || "活动时间"}
                                    rightText={this.props.placeholder || "请选择活动时间"}/>;
        }

        return (
            <>
                <input {...rest} disabled={disabled} readOnly={readOnly}
                       ref={_ => this.#ReactTimeRef = _}
                       style={{
                           position: 'absolute',
                           opacity: '0',
                           width: '100%',
                           height: '35px',
                           zIndex: 0
                       }}
                       type="time"
                       id={this.#id}
                       onChange={this.timeChange.bind(this)}/>
                <label className={["--react-native-date"].concat(formatClassList(className)).join(' ')}
                       style={{
                           position: 'relative',
                           zIndex: 1
                       }}
                       htmlFor={this.#id}>
                    <ReactLinkSelect placeholder={title || label} highlight={!!this.value}>
                        <span>{this.value ? DateFormat(this.value, format || 'HH:MM') : placeholder}</span>
                    </ReactLinkSelect>
                </label>
            </>
        );
    }
}

class DynamicUploadInput extends React.Component {
    #fileElement;

    async onClick(e) {
        if (this.props.onBeforeClick?.(e) === true) {
            e.preventDefault();
            e.stopPropagation();
            return;
        }
        if (this.props.disabled) {
            return;
        }
        if (BROWSERTYPES.isWeChat) {
            e.preventDefault();
            e.stopPropagation();

            await this.props.onClick?.(e);
            let result = await WeChat.ChooseImage(this.props.count || 1);

            if (result === false) {
                return;
            }
            e.files = result;
            this.onChange(e);
        } else {
            this.props.onClick?.(e);
        }

    }

    async onChange(e) {
        e.stopPropagation();
        e.preventDefault();
        if (this.inUpload === true) {
            return;
        }

        if (this.props.disabled) {
            return;
        }


        if (!BROWSERTYPES.isWeChat) {
            e.files = this.#fileElement.files;
        }

        this.inUpload = true;

        if (e.files instanceof FileList && !BROWSERTYPES.isWeChat) {
            let files = [];
            Array.from(e.files).forEach(n => {
                files.push(n);
            });

            if (this.props.upload !== false) {
                this.props.onBeforeUpload?.();
                let resList = await Promise.all(files.map(x => UploadController.UploadImage(x)));
                let errors = resList.filter(x => x.STATUS !== 0);

                if (errors.length > 0) {
                    //复数和单个的提示区别
                    let errorMessage = errors.length === 1 ? '图片上传失败' : '存在个别图片上传失败';

                    notify(errorMessage);
                }

                e.files = resList.filter(x => x.STATUS === 0).map(x => x?.DATA || '');
                try {
                    this.#fileElement.value = null;
                } catch (e) {

                }
            }
        } else if (BROWSERTYPES.isWeChat) {
            if (this.props.upload !== false) {
                loading('上传中');
                let resList = await Promise.all(e.files.map(x => WeChatController.UploadImage(x.serverId, x.fileName)));
                loaded();
                let errors = resList.filter(x => x.STATUS !== 0);

                if (errors.length > 0) {
                    //复数和单个的提示区别
                    let errorMessage = errors.length === 1 ? '图片上传失败' : '存在个别图片上传失败';

                    notify(errorMessage);
                }
                e.files = resList.filter(x => x.STATUS === 0).map(x => x?.DATA || '');
            }
        }

        this.inUpload = false;
        this.props.onChange?.(e);
    }

    render() {
        let {
            onClick, onChange, ref, count,
            upload, onBeforeClick, onBeforeUpload,
            ...rest
        } = this.props || {};

        return (
            <input ref={_ => this.#fileElement = _} {...rest} type={"file"} accept="image/*" multiple=""
                   onClick={this.onClick.bind(this)} onChange={this.onChange.bind(this)}
                   onInput={this.onChange.bind(this)}/>
        );
    }
}

export {
    ReactSearch,
    LinkSelectable,
    ReactInput,
    ReactSelect,
    ReactLinkSelect,
    ReactTextArea,
    ReactDatePicker,
    ReactUpload,
    ReactNativeDate,
    DynamicUploadInput,
    ReactNativeTime,
    ReactTimePicker,
};
